package com.example.camerademoexcercies1;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;
import android.util.Size;
import android.util.SparseIntArray;
import android.view.KeyEvent;
import android.view.MenuItem;
import android.view.Surface;
import android.view.TextureView;
import android.view.View;
import android.widget.HorizontalScrollView;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.PopupMenu;
import androidx.constraintlayout.widget.ConstraintLayout;

import com.example.camerademoexcercies1.tool.LogTool;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class SimplifyRecorder2 extends AppCompatActivity implements View.OnClickListener, PopupMenu.OnMenuItemClickListener {

    /**
     * 问题总结：
     * 1.可以预览 但是怎么使用mediaRecorder
     * 2.停止预览 得到一个新requestBuilder，添加参数然后添加target：textureView和mediaRecorder的surface
     * 3.两个surface都丢到createSession的surfaceList中
     */

    //记录用户首次点击返回键的时间
    private long firstTime = 0;
    private TextureView textureView;
    private Surface previewSurface;
    private Surface mediaRecorderSurface;
    private ImageButton rotateButton;
    private ImageButton btn_recorder;
    private boolean isRecording;
    private String cameraId;
    private ConstraintLayout bottom_linearLayout;
    private CameraManager cameraManager;
    private CameraCharacteristics cameraCharacteristics;
    private HandlerThread handlerThread;
    private Handler mBackgroundHandler;
    private MediaRecorder recorder;
    private CameraDevice cameraDevice;
    private CaptureRequest.Builder previewBuilder;
    private CameraCaptureSession previewSession;
    private File videoFile;
    private int optimalSizeWidth;
    private int optimalSizeHeight;
    private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
    private String[] tags;
    private LinearLayout linear_tags;
    private HorizontalScrollView hScroll;
    private Long nowTimer = 0L;
    private Long oldTimer = 0L;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_simplify_recorder2);
        startBackgroundThread();
        initCameraManager("0");
        initEvent();
        initTextureView();
    }

    //    点击事件
    @Override
    public void onClick(View v) {
        if (v.getId() == R.id.btn_simple_record) {
//            开始录制转停止录制
            if (isRecording) {
                recorder.stop();
                recorder.release();
                recorder = null;
                say("————+++++++++__)stop recording————");
                stopPreviewSession();
                isRecording = false;
                new CreatePreviewSessionThread().run();
                btn_recorder.setImageResource(R.drawable.icon_recorder_white);
                bottom_linearLayout.setAlpha(1);
            } else {
                //  暂停预览，准备media，初始化，camera再开启一个预览会话
                recorder.start();
                say("————start recording————");
                isRecording = true;
                btn_recorder.setImageResource(R.drawable.icon_recorder_red);
                bottom_linearLayout.setAlpha(0.1F);
            }
        } else if (v.getId() == R.id.btn_simple_rotate) {
            stopCamera();
            if (cameraId.equals("0")) {
                initCameraManager("1");
            } else initCameraManager("0");
            new OpenCameraThread().run();
        }/* else if (v.getId() == R.id.btn_resolution_menu) {
            PopupMenu popupMenu = new PopupMenu(this, v);
            //  获取菜单填充器
            MenuInflater inflater = popupMenu.getMenuInflater();
            //  填充菜单
            inflater.inflate(R.menu.simple_camera_menu, popupMenu.getMenu());
            //  绑定菜单项的点击事件
            popupMenu.setOnMenuItemClickListener(this);
            popupMenu.show();
        }*/

    }

    //  菜单点击事件
    @Override
    public boolean onMenuItemClick(MenuItem item) {
        if (item.getItemId() == R.id.menu_resolution_option1) {
            say("option1");
        } else if (item.getItemId() == R.id.menu_resolution_option2) {
            say("option2");
        } else if (item.getItemId() == R.id.menu_resolution_option3) {
            say("option3");
        } else if (item.getItemId() == R.id.menu_resolution_option4) {
            say("option4");
        }
        return false;
    }

    //    初始化cameraManager和cameraCharacteristics还有CameraId（manager开摄像头用）
    private void initCameraManager(String id) {
        cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
        cameraId = id;
        say("初始化cameraManager&相机ID为：" + cameraId);
        try {
            /*有可能该摄像头不存在*/
            cameraCharacteristics = cameraManager.getCameraCharacteristics(cameraId);
            say("初始化对应相机ID的cameraCharacteristics");
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    //    初始化画布，就绪后打开摄像头
    private void initTextureView() {
        textureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
            @Override
            public void onSurfaceTextureAvailable(@NonNull SurfaceTexture surface, int width, int height) {
                Size optimalSize = getOptimalSize(width, height);
                say("optimalSize - "+optimalSize.toString());
                optimalSizeWidth = optimalSize.getWidth();
                optimalSizeHeight = optimalSize.getHeight();
                say("Texture可用,计算得到最佳尺寸：" + optimalSize.getWidth() + "*" + optimalSize.getHeight() + " 初始化Surface");
                surface.setDefaultBufferSize(optimalSizeWidth, optimalSizeHeight);
                previewSurface = new Surface(surface);
                new OpenCameraThread().run();
            }

            @Override
            public void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surface, int width, int height) {
                say("onSurfaceTextureSizeChanged");
            }

            @Override
            public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surface) {
                say("onSurfaceTextureDestroyed");
                return false;
            }

            @Override
            public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) {
            }
        });
    }

    //    绑定组件、事件
    private void initEvent() {
        isRecording = false;
        cameraId = "0";
        btn_recorder = findViewById(R.id.btn_simple_record);
        textureView = findViewById(R.id.texture_recorder_view);
        rotateButton = findViewById(R.id.btn_simple_rotate);
        cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
        bottom_linearLayout = (ConstraintLayout) findViewById(R.id.bottom_linearLayout);

        linear_tags = findViewById(R.id.linear_tags);
        hScroll = findViewById(R.id.hScroll);
        tags = new String[]{"连拍", "拍照", "录像"};
        initTags();

        btn_recorder.setOnClickListener(this);
        rotateButton.setOnClickListener(this);
    }

    @SuppressLint("ResourceAsColor")
    private void initTags() {
        //装标题控件的集合
        List<View> viewList = new ArrayList<>();
        for (int i = 0; i < tags.length; i++) {
            TextView textView = new TextView(SimplifyRecorder2.this);
            textView.setTextSize(15);
            textView.setTextColor(0xffffffff);
            if (i == 0) {
                textView.setTextColor(this.getResources().getColor(R.color.blue));
            }


            textView.setText(tags[i]);
            //LinearLayout中的孩子的定位参数
            LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT);
            layoutParams.setMargins(25, 0, 25, 0);//设置左上右下四个margin值;
            //layoutParams是让linearLayout知道如何摆放自己孩子的位置的;
            linear_tags.addView(textView, layoutParams);
            viewList.add(textView);
        }

    }

    //    停止预览会话，因为参数不同所以需要清除重新创建
    private void stopPreviewSession() {
        try {
            previewSession.stopRepeating();
            previewSession.close();
            previewSession = null;
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    //    直接关闭当前摄像头，因为要切换了
    private void stopCamera() {
        cameraDevice.close();
        cameraDevice = null;
    }

    //    初始化mediaRecorder
    private void initMediaRecorder() {
        File videoRootPath = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM),
                "MediaRecorderStorage");
        if (!videoRootPath.exists() && !videoRootPath.mkdir()) {
            say("根目录:videoRootPath(" + videoRootPath.toString() + ")创建失败");
        } else {
            videoFile = new File(videoRootPath, "video" + System.currentTimeMillis() + ".mp4");
            say("输出文件 : " + videoFile);
        }
        stopPreviewSession();
        recorder = new MediaRecorder();
        //    这两项需要放在setOutputFormat之前
        recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        recorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
        recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
        recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
        recorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
        recorder.setVideoSize(optimalSizeWidth, optimalSizeHeight);
        recorder.setVideoEncodingBitRate(10000000);
        recorder.setVideoFrameRate(30);
        if (cameraId.equals("0")) {
            recorder.setOrientationHint(90);
        } else {
            recorder.setOrientationHint(270);
        }
        //        指定surface
        SurfaceTexture surfaceTexture = textureView.getSurfaceTexture();
        surfaceTexture.setDefaultBufferSize(optimalSizeWidth, optimalSizeHeight);
        previewSurface = new Surface(surfaceTexture);
        recorder.setPreviewDisplay(previewSurface);
        //        设置记录会话的最大持续时间（毫秒）
        recorder.setMaxDuration(30 * 1000);
        recorder.setOutputFile(videoFile.getAbsolutePath());
        say("recorder参数初始化完成");
        try {
            //  没懂这个surface是干嘛的
            recorder.prepare();
            say("recorder准备就绪");
            mediaRecorderSurface = recorder.getSurface();
            previewBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
            previewBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_VIDEO);
            previewBuilder.addTarget(mediaRecorderSurface);
            previewBuilder.addTarget(previewSurface);

            cameraDevice.createCaptureSession(Arrays.asList(previewSurface, mediaRecorderSurface), new CameraCaptureSession.StateCallback() {
                @Override
                public void onConfigured(@NonNull CameraCaptureSession session) {
                    previewSession = session;
                    try {
                        previewSession.setRepeatingRequest(previewBuilder.build(), null, mBackgroundHandler);
                    } catch (CameraAccessException e) {
                        e.printStackTrace();
                    }
                }

                @Override
                public void onConfigureFailed(@NonNull CameraCaptureSession session) {

                }
            }, mBackgroundHandler);
            say("mediaRecorder 初始化完成");
        } catch (IOException | CameraAccessException e) {
            e.printStackTrace();
        }
    }

    //    获取当前Characteristic分辨率最高的Size
    public Size getOptimalSize(int textureWidth, int textureHeight) {
        try {
            cameraCharacteristics = cameraManager.getCameraCharacteristics(cameraId);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
        StreamConfigurationMap configurationMap = //一份详细的配置表
                cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
        Size[] sizeList = configurationMap.getOutputSizes(SurfaceTexture.class); //提供一个可输出Size的类
        List<Size> readyList = new ArrayList<>();
//            先找尺寸接近的，再找其中分辨率最高的
        float bestRatio = (float) textureHeight / textureWidth;
        int maxSize = 0;
        for (Size size : sizeList) {
            if (Math.abs(((float) size.getWidth() / size.getHeight() - bestRatio)) < 0.1) {
                readyList.add(size);
            }
        }
        say("第一轮筛选的size有：" + readyList.toString());
        for (Size size : readyList) {
            if (size.getWidth() > maxSize) {
                maxSize = size.getWidth();
                sizeList[0] = size;
            }
        }
        return sizeList[0];
    }

    //    让所有的回调跑在这个非主线程上
    private void startBackgroundThread() {
        handlerThread = new HandlerThread("CameraThread");
        handlerThread.start();
        mBackgroundHandler = new Handler(handlerThread.getLooper());
        say("开启后台线程");
    }

    //    打印
    public void say(String word) {
        if (oldTimer == 0L) {
            oldTimer = System.currentTimeMillis();
            LogTool.log("开始计时\t" + word);
            Log.e("TAG","这是Recorder2++++++++++++"+word);
        } else {
            nowTimer = System.currentTimeMillis();
            long dist = nowTimer - oldTimer;
            if (dist < 5000L) {
                LogTool.log(("耗时：" + (dist) + "\t\t") + word);
                Log.e("TAG","这是Recorder2++++++++++++"+word);
                oldTimer = nowTimer;
            } else {
                LogTool.log("超时：" + (dist) + "\t\t" + word);
                oldTimer = 0L;
            }
        }
    }

    //    返回退出功能
    @Override
    public boolean onKeyUp(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
            long secondTime = System.currentTimeMillis();
            if (secondTime - firstTime > 2000) {
                Toast.makeText(this, "再按一次退出程序", (int) 2000).show();
                firstTime = secondTime;
                return true;
            } else {
                finish();
                System.exit(0);
            }
        }
        return super.onKeyUp(keyCode, event);
    }

    //    相机开启线程
    public class OpenCameraThread implements Runnable {

        @Override
        public void run() {
            openCamera();
        }

        //    相机开启
        @SuppressLint("MissingPermission")
        private void openCamera() {
            try {
                cameraManager.openCamera(cameraId, new CameraDevice.StateCallback() {
                    @Override
                    public void onOpened(@NonNull CameraDevice camera) {
                        cameraDevice = camera;
                        say("开启" + (cameraId.equals("0") ? "后置摄像头" : "前置摄像头") + ",初始化Device，开始会话创建线程");
                        new CreatePreviewSessionThread().run();
                    }

                    @Override
                    public void onDisconnected(@NonNull CameraDevice camera) {

                    }

                    @Override
                    public void onError(@NonNull CameraDevice camera, int error) {

                    }
                }, mBackgroundHandler);
            } catch (CameraAccessException e) {
                e.printStackTrace();
            }
        }
    }

    //    创建预览会话线程
    public class CreatePreviewSessionThread implements Runnable {

        @Override
        public void run() {
            createPreviewSession();
        }

        //    创建预览会话
        private void createPreviewSession() {
            try {
//                if (previewBuilder == null) {
                previewBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
                previewBuilder.addTarget(previewSurface);
                say("添加previewSurface(" + previewSurface + ")为Target");

                // 自动对焦
                previewBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
                // 闪光灯
                previewBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
                // 根据摄像头方向对保存的照片进行旋转，使其为"自然方向"
                Integer mCameraSensorOrientation = cameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
                previewBuilder.set(CaptureRequest.JPEG_ORIENTATION, mCameraSensorOrientation);
                // 人脸检测模式
                previewBuilder.set(CaptureRequest.STATISTICS_FACE_DETECT_MODE, CameraCharacteristics.STATISTICS_FACE_DETECT_MODE_SIMPLE);
                say("初始化完对应预览builder和参数");
//                } else say("使用已经初始化完成的builder");
                // 创建循环请求
                //        指定surface
                SurfaceTexture surfaceTexture = textureView.getSurfaceTexture();
                surfaceTexture.setDefaultBufferSize(optimalSizeWidth, optimalSizeHeight);
                previewSurface = new Surface(surfaceTexture);

                if (cameraDevice != null) {
                    cameraDevice.createCaptureSession(Arrays.asList(previewSurface), new CameraCaptureSession.StateCallback() {
                        @Override
                        public void onConfigured(@NonNull CameraCaptureSession session) {
                            previewSession = session;
                            try {
                                previewSession.setRepeatingRequest(previewBuilder.build(), null, mBackgroundHandler);
                                say("使用该cameraDevice创建的session启动预览");
                                initMediaRecorder();
                            } catch (CameraAccessException e) {
                                e.printStackTrace();
                            }
                        }

                        @Override
                        public void onConfigureFailed(@NonNull CameraCaptureSession session) {

                        }
                    }, mBackgroundHandler);
                } else say("cameraDevice 为空,无法创建captureSession");

            } catch (CameraAccessException e) {
                e.printStackTrace();
            }
        }
    }
}